package cn.tedu.submarine;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Random;
import java.util.Arrays;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

/** 整个游戏窗口  */
public class World extends JPanel{
    public static final int WIDTH = 641; //窗口的宽
    public static final int HEIGHT = 479; //窗口的高

    public static final int START = 0; //启动状态
    public static final int RUNNING = 1; //运行状态
    public static final int GAME_OVER = 2; //游戏结束状态
    private int state = START; //当前状态(默认为启动状态)

    private Battleship ship = new Battleship(); //战舰
    private SeaObject[] submarines = {}; //潜艇数组
    private SeaObject[] thunders = {}; //雷数组
    private Bomb[] bombs = {};

    /** 生成潜艇(侦查潜艇、鱼雷潜艇、水雷潜艇)对象*/
    public SeaObject nextSubmarine(){
        Random rand = new Random();
        int type = rand.nextInt(20);
        if (type<10){
            return new ObserveSubmarine();
        }else if(type<15){
            return new TorpedoSubmarine();
        }else {
            return new MineSubmarine();
        }
    }

    private int subEnterIndex = 0; //潜艇入场计数
    /** 潜艇入场*/
    public void submarineEnterAction(){ //10毫秒执行一次
        subEnterIndex++; //每10毫秒增1
        if (subEnterIndex%40 == 0){
            SeaObject obj = nextSubmarine(); //生成一个潜艇对象
            submarines = Arrays.copyOf(submarines,submarines.length+1); //扩容
            submarines[submarines.length-1] = obj; //将obj添加到submarines的最后一个元素
        }
    }

    private int thunderEnterIndex = 0;//雷入场的计数
    /** 发射雷(水雷，鱼雷)*/
    public void thunderEnterAction(){ //10毫秒执行一次
        thunderEnterIndex++; //每10毫秒增1
        if (thunderEnterIndex%100 ==0){ //每一秒钟走一次
            for (int i = 0; i < submarines.length; i++) {
                SeaObject obj = submarines[i].shootThunder();
                if (obj!=null){
                    thunders = Arrays.copyOf(thunders,thunders.length+1);
                     thunders[thunders.length-1] = obj;
                }
            }
        }
    }

    /** 潜艇和雷移动*/
    public void stepAction(){ //每10毫秒走一次
        for (int i = 0; i < submarines.length; i++) {
            submarines[i].step(); //潜艇移动
        }
        for (int i = 0; i < thunders.length; i++) {
            thunders[i].step(); //雷移动
        }
        for (int i = 0; i < bombs.length; i++) {
            bombs[i].step();
        }
    }

    /** 删除海洋对象---避免内存泄漏*/
    public void outOfBoundsAction(){ //每10秒走一次
        for (int i = 0; i < submarines.length; i++) {
            if (submarines[i].isOutOfBounds() || submarines[i].isDead()){
                submarines[i] = submarines[submarines.length-1]; //将越界潜艇替换为最后一个
                submarines = Arrays.copyOf(submarines,submarines.length-1); //缩容
            }
        }
        for (int i = 0; i < thunders.length; i++) {
            if (thunders[i].isOutOfBounds()){
                thunders[i] = thunders[thunders.length-1];
                thunders = Arrays.copyOf(thunders,thunders.length-1);
            }
        }
        for (int i = 0; i < bombs.length; i++) {
            if (bombs[i].isOutOfBounds()){
                bombs[i] = bombs[bombs.length-1];
                bombs = Arrays.copyOf(bombs,bombs.length-1);
            }
        }
    }

    private int score = 0; //玩家的得分
    /** 深水炸弹与潜艇的碰撞*/
    public void bombBangAction(){ //每10毫秒走一次
        for (int i = 0; i < bombs.length; i++) {
            Bomb b = bombs[i];
            for (int j = 0; j < submarines.length; j++) {
                SeaObject s = submarines[j];
                if (b.isLive() && s.isLive() && s.isHit(b)){
                    s.goDead(); //潜艇去死
                    b.goDead(); //深水炸弹去死
                    //很妙的东西
                    if (s instanceof EnemyScore){
                        EnemyScore es = (EnemyScore)s;
                        score += es.getScore();
                    }
                    if (s instanceof EnemyAward){
                        EnemyAward ea = (EnemyAward) s;
                        int life = ea.getLife();
                        ship.addLife(life);
                    }
                }
            }

        }
    }

    /** 雷与战舰的碰撞*/
    public void thunderBangAction(){ //每10毫秒走一次
        for (int i = 0; i < thunders.length; i++) {
            SeaObject t = thunders[i];
            if (t.isLive() && ship.isLive() && t.isHit(ship)){
                t.goDead(); //雷去死
                ship.subtractLife(); //命数减减
            }
        }
    }

    /** 检测游戏结束*/
    public void checkGameOverAction(){ //每10毫秒走一次
        if(ship.getLife() <= 0){ //若战舰的命数<=0,表示游戏结束了，则...
            state = GAME_OVER;
        }
    }

    /** 启动程序的执行*/
    public void action(){
        //如下侦听器代码---不要求掌握
        KeyAdapter k = new KeyAdapter() {
            /** 重写keyRelease()键盘弹起事假*/
            public void keyReleased(KeyEvent e) {
                if(e.getKeyCode()==KeyEvent.VK_SPACE){
                    switch(state){
                        case START: //启动状态时，按空格修改为运行状态
                            state = RUNNING;
                            break;
                        case RUNNING: //运行状态结束时，按发射炸弹
                            Bomb obj = ship.shoot(); //获取战舰发射出来的深水炸弹
                            bombs = Arrays.copyOf(bombs,bombs.length+1);
                            bombs[bombs.length-1] = obj;
                            break;
                        case GAME_OVER: //结束状态时，按空格修改为启动状态
                            //清理现场(数据归零)
                            ship = new Battleship();
                            submarines = new SeaObject[0];
                            thunders = new SeaObject[0];
                            bombs = new Bomb[0];
                            score = 0;

                            state = START;
                    }
                }
                if (e.getKeyCode()==KeyEvent.VK_LEFT){ //按下左键战舰左移
                        ship.moveLeft();
                }
                if (e.getKeyCode()==KeyEvent.VK_RIGHT){ //按下右键战舰右移
                        ship.moveRight();
                }

            }
        };  //键盘侦听器
        this.addKeyListener(k); //将键盘侦听器添加到当前窗口

        Timer timer = new Timer(); //定时器对象
        int  intervel = 10; //定时间隔（以毫秒为单位）
        timer.schedule(new TimerTask() {
            public void run() { //定时干的事--每隔10毫秒自动执行
                if (state == RUNNING){ //仅在运行态中走
                    submarineEnterAction();//潜艇入场
                    thunderEnterAction(); //雷入场
                    stepAction(); //海洋对象移动
                    outOfBoundsAction(); //移除海洋对象
                    bombBangAction(); //深水炸弹与潜艇的碰撞
                    thunderBangAction(); //雷与战舰的碰撞
                    checkGameOverAction(); //检测游戏结束
                }
                repaint(); //重新调用paint方法
            }
        }, intervel, intervel);
    }

    @Override
    public void paint(Graphics g){ //每10秒执行一次
        switch(state){
            case START: //启动状态时画启动图
                Images.start.paintIcon(null,g,0,0);
                break;
            case GAME_OVER: //结束状态时画结束图
                Images.gameover.paintIcon(null,g,0,0);
                break;
            case RUNNING: //运行状态画运行图
                Images.sea.paintIcon(null,g,0,0);
                ship.paintImage(g); //画战舰
                for (int i = 0; i < submarines.length; i++) {
                    submarines[i].paintImage(g);
                }
                for (int i = 0; i < thunders.length; i++) {
                    thunders[i].paintImage(g);
                }
                for (int i = 0; i < bombs.length; i++) {
                    bombs[i].paintImage(g);
                }
                g.drawString("SCORE: "+score,200,50);
                g.drawString("LIFE: "+ship.getLife(),400,50);
        }
    }

    public static void main(String[] args) {
        World world = new World();
        JFrame frame = new JFrame();
        world.setFocusable(true);
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH+16,HEIGHT+39);
        frame.setLocationRelativeTo(null);

        frame.setVisible(true); //1)设置窗口可见， 2)尽快调用paint()f方法

        world.action(); //启动程序的执行
    }
}



//接口是对继承的单根性的扩展---多继承---
/*
    1. 问：为什么将那一堆引用设计在main的外面？
        若将引用设计在main中，意味着引用就只能在main中访问了
        而World类后期会设计很多的方法，这些方法需要操作那一堆引用
        所以将引用设计在main的外面，以扩大作用范围
    2. 问： 为什么要单独创建action？
        因为main是static的，在static的方法中是无法访问那一堆引用的
        所以要单独创建一个非static的方法action（）来测试
        ------------static的内容到后面的面向对象第五天时讲解
    3.
 */